package com.fywsy.fyweb.controller;

import com.fywsy.fyweb.entity.*;
import com.fywsy.fyweb.entity.projection.ItemProjection;
import com.fywsy.fyweb.repository.*;
import com.fywsy.fyweb.strategy.GameStrategyFactory;
import com.fywsy.fyweb.utils.LocalDateTimeUtils;
import com.fywsy.fyweb.utils.TextUtils;
import io.github.resilience4j.ratelimiter.annotation.RateLimiter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("/backend")
public class BackendController {

    @Autowired
    GameRepository gameRepository;

    @Autowired
    QufuRepository qufuRepository;

    @Autowired
    GongnengRepository gongnengRepository;

    @Autowired
    ItemRepository itemRepository;

    @Autowired
    ItemTotalRepository itemTotalRepository;

    @Autowired
    CdkRepository cdkRepository;

    @Autowired
    SendLogRepository sendLogRepository;

    @Autowired
    GameLinkRepository gameLinkRepository;

    GameStrategyFactory gameStrategyFactory;


    @Autowired
    public BackendController(GameStrategyFactory gameStrategyFactory) {
        this.gameStrategyFactory = gameStrategyFactory;
    }

    /**
     * 查询后台基本信息
     *
     * @param params
     * @return
     */
    @PostMapping("/base")
    public ResponseBackend base(@RequestBody RequestParams params) {

        Game game = gameRepository.findById(params.gameId).get();
        List<Qufu> qufus = qufuRepository.findAllByEnableAndGameId(true, params.gameId);
        List<Gongneng> gongnengs = gongnengRepository.findAllByEnableAndGameIdOrderByWeightDescIdAsc(true, params.gameId);

        ResponseBackend response = new ResponseBackend();
        response.game = game;
        response.qufu = qufus;
        response.gongneng = gongnengs;
        response.links = gameLinkRepository.findAllByEnableAndLocationAndGameId(true,1,params.gameId);
        return response;
    }


    /**
     * 获取全部道具
     *
     * @return
     */
    @PostMapping("/items")
    public List<ItemProjection> items(@RequestBody RequestParams params) {
        List<ItemProjection> items = itemRepository.findAllByEnableAndGameIdAndGongnengId(true, params.gameId, params.gongnengId);
        return items;
    }


    /**
     * 发送道具
     *
     * @param item
     * @return
     */
    @PostMapping("send")
    @RateLimiter(name = "backendLimit", fallbackMethod = "rateLimitFallback")
    public ResponseEntity<?> send(@RequestBody SendItem item) {

        if (item.gameId == 0 || item.gongnengId == 0) {
            return ResponseEntity.badRequest().body("非法请求，请联系客服");
        }

        /**
         * 表单校验
         */
        if (TextUtils.isEmpty(item.uid)) {
            return ResponseEntity.badRequest().body("授权信息为空!");
        }

        Gongneng gongneng = gongnengRepository.findFirstByGid(item.gongnengId);
        if (!gongneng.enable) {
            return ResponseEntity.badRequest().body("功能已失效");
        }
        if (gongneng.req && TextUtils.isEmpty(item.itemId)) {
            return ResponseEntity.badRequest().body("请选择道具");
        }

        if (gongneng.num && TextUtils.isEmpty(item.number)) {
            return ResponseEntity.badRequest().body("数量不能为空！");
        }

        if (gongneng.num && !TextUtils.isNumber(item.number)) {
            return ResponseEntity.badRequest().body("请输入正确的数量");
        }

        /**
         * 判断cdk情况
         * 如果是天卡的话，可能使用很多张，取最近那一个
         */
        Cdk cdk = cdkRepository.findFirstByGameIdAndUidAndBanOrderByUseTimeDesc(item.gameId, item.uid, false);
        if (cdk == null) {
            return ResponseEntity.badRequest().body(item.uid + "暂未激活权限");
        }
        if (cdk.ban) {
            return ResponseEntity.badRequest().body("激活码失效，请重新激活");
        }

        if (LocalDateTimeUtils.isOverGivenDays(cdk.useTime, cdk.validDay)) {
            return ResponseEntity.badRequest().body(item.uid + "激活时间已过，请重新激活");
        }
        ItemTotal total = null;
        /**
         * 判断物品最大数量
         * 更新道具发送次数
         */
        String itemName = null;
        if (!TextUtils.isEmpty(item.itemId)) {
            Item dbItem = itemRepository.findFirstByGameIdAndGongnengIdAndC(item.gameId, item.gongnengId, item.itemId);
            if (dbItem != null && dbItem.enable) {
                if(gongneng.num) {
                    long number = Long.parseLong(item.number);
                    if (number > dbItem.getMax()) {
                        return ResponseEntity.badRequest().body("数量最大" + dbItem.max);
                    }
                }

                if(dbItem.dayCount != null && dbItem.dayCount > 0) {
                    total = getItemTotal(item.gameId, dbItem.id, item.uid, dbItem.dayCount);
                    if(total.left < 0) {
                        return ResponseEntity.badRequest().body("已超量" + Math.abs(total.left));
                    } else if(total.left == 0) {
                        return ResponseEntity.badRequest().body("今日已发");
                    } else {
                        item.number = String.valueOf(total.left);
                    }
                }
                dbItem.t++;
                itemName = dbItem.n;
                itemRepository.save(dbItem);
            } else {
                return ResponseEntity.badRequest().body("无此道具!");
            }
        }
        // 分发到不同的位置处理
        String result = gameStrategyFactory.executeStrategy(item.gameId, item.gongnengId, item);
        if (!result.contains("成功") && !result.contains("\\u6210\\u529f")) return ResponseEntity.badRequest().body(result);
        if(total != null) {
            itemTotalRepository.save(total);
        }

        try {
            //保存发送日志，以便于判断游戏实际在玩人数和其他
            SendLog log = new SendLog();
            log.uid = item.uid;
            log.gameId = item.gameId;
            log.gongnengId = item.gongnengId;
            log.number = item.number;
            log.itemId = item.itemId;
            log.itemName = TextUtils.isEmpty(itemName) ? gongneng.name : itemName;
            sendLogRepository.save(log);
        } catch (Exception e) {
            System.out.println("发送日志保存失败");
            e.printStackTrace();
        }

        return ResponseEntity.ok(result);

    }


    public ResponseEntity<?> rateLimitFallback(SendItem item,Exception ex) {
        ex.printStackTrace();
        System.out.println(item.uid + " -刷太快了");
        return ResponseEntity.badRequest().body("点太快啦~");
    }


    /**
     * 获取剩余可以发送数量,并更新到对象内,外部保存即可
     * @param gameId        game表id
     * @param itemId        item表id
     * @param uid           开通信息
     * @return              剩余可发数量,如果是负,则可能是dayCount 调小了,则不允许发送,
     */
    private ItemTotal getItemTotal(long gameId, long itemId, String uid, long dayCount) {
        ItemTotal item = itemTotalRepository.findFirstByGameIdAndItemIdAndUid(gameId, itemId, uid);
        if(item == null) {
            item = new ItemTotal(gameId, itemId, uid);
        }
        Game game = gameRepository.findById(gameId).orElse(null);

        //计算天数差
        long between = ChronoUnit.DAYS.between(game.createTime.toLocalDate(), LocalDate.now()) + 1;
        long left = dayCount * between - item.total;
        if(left > 0) {
            item.total += left;
        }
        item.left = left;
        return item;
    }
}


